package com.ccteam.fluidmusic.widget

import android.content.Context
import android.content.res.ColorStateList
import android.graphics.Color
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.widget.FrameLayout
import androidx.core.content.res.use
import androidx.core.view.isVisible
import androidx.paging.LoadState
import com.ccteam.fluidmusic.R
import com.ccteam.fluidmusic.databinding.GlobalStatusLayoutBinding
import com.ccteam.fluidmusic.view.bean.ErrorMessage
import com.ccteam.fluidmusic.view.bean.LoadMessage
import com.ccteam.network.ApiError
import com.ccteam.network.exception.ApiException
import com.ccteam.shared.utils.EMPTY_STRING
import com.google.android.material.color.MaterialColors

/**
 * @author Xiaoc
 * @since 2021/2/20
 *
 * 状态视图，通过设置对应状态显示对应内容
 *
 */
class StatusView: FrameLayout {

    private val binding = GlobalStatusLayoutBinding.inflate(LayoutInflater.from(context),this,true)

    /**
     * 空状态的资源ID
     */
    private var emptyResourceId: Int = R.drawable.ic_empty

    /**
     * 网络错误的资源ID
     */
    private var networkFailResourceId: Int = R.drawable.ic_network_fail

    /**
     * 未知错误的资源ID
     */
    private var unknownFailResourceId: Int = R.drawable.ic_music_network_fail

    /**
     * 是否开启重试按钮
     */
    private var enableRetry: Boolean = true

    private var emptyText: String = EMPTY_STRING

    private var colorTint: Int = Color.BLACK

    constructor(context: Context): this(context,null)

    constructor(context: Context,attrs: AttributeSet?): this(context,attrs,R.style.FluidMusic_StatusView)

    constructor(context: Context,attrs: AttributeSet?,defStyleAttr: Int): super(context,attrs,defStyleAttr){

        val ta = context.obtainStyledAttributes(attrs,R.styleable.StatusView)
        ta.use {
            emptyResourceId = it.getResourceId(R.styleable.StatusView_emptyStatus,R.drawable.ic_empty)
            enableRetry = it.getBoolean(R.styleable.StatusView_enableRetry,true)
            emptyText = it.getString(R.styleable.StatusView_emptyText) ?: resources.getString(R.string.description_empty_info)
            networkFailResourceId = it.getResourceId(R.styleable.StatusView_networkFailStatus,R.drawable.ic_network_fail)
            unknownFailResourceId = it.getResourceId(R.styleable.StatusView_unknownFailStatus,R.drawable.ic_music_network_fail)
            colorTint = it.getColor(R.styleable.StatusView_colorTint,MaterialColors.getColor(binding.root,R.attr.colorOnSurface))
        }
        binding.btnRetry.isVisible = enableRetry
    }

    companion object{
        private val emptyErrorMessage = ErrorMessage(errorCode = ApiError.dataIsNullCode)
    }

    /**
     * 改变加载状态
     * @param isLoading 是否是加载中，如果为true，则显示加载进度，否则隐藏加载进度
     */
    fun changeToLoadingStatus(isLoading: Boolean){
        binding.progressLoading.isVisible = isLoading
    }

    /**
     * 设置图标和文本的颜色填充
     */
    fun setIconTextTint(color: Int){
        binding.btnRetry.setTextColor(color)
        binding.ivStatus.imageTintList = ColorStateList.valueOf(color)
        binding.tvErrorInfo.setTextColor(color)
    }

    /**
     * 改变错误状态
     * 该方法针对分页库 [androidx.paging.Pager] 的状态进行
     * 需要自行传入 [isEmpty] 布尔值告诉当前状态是否为空状态
     *
     * @param loadState 分页库加载状态
     * @param isEmpty 是否为空状态
     */
    fun changeToErrorStatus(loadState: LoadState,isEmpty: Boolean = false){
        if(isEmpty && loadState is LoadState.NotLoading){
            changeToErrorStatus(emptyErrorMessage)
            return
        }
        if(loadState is LoadState.Error){
            val errorMessage = if(loadState.error is ApiException){
                val error = loadState.error as ApiException
                ErrorMessage(error.errorMsg,error.errorCode)
            } else {
                ErrorMessage(loadState.error.message)
            }
            changeToErrorStatus(errorMessage)
        } else {
            changeToErrorStatus(null)
        }

    }

    /**
     * 改变错误状态
     * 基于错误信息，改变对应错误内容显示
     * 如果不想显示错误信息，传入 null
     *
     * @param errorMessage 错误信息，如果为null会隐藏错误显示
     */
    fun changeToErrorStatus(errorMessage: ErrorMessage?){
        setErrorStatus(errorMessage)
    }

    /**
     * 改变错误状态
     * 该方法针对自定义的 [LoadMessage] 状态所适用
     * 会自动根据不同的Load状态切换不同的内容
     *
     * @param loadMessage 加载状态
     */
    fun changeToErrorStatus(loadMessage: LoadMessage){
        when (loadMessage) {
            is LoadMessage.Error -> {
                changeToErrorStatus(loadMessage.errorMessage)
            }
            is LoadMessage.Empty -> {
                changeToErrorStatus(emptyErrorMessage)
            }
            else -> {
                changeToErrorStatus(null)
            }
        }

    }

    /**
     * 设置错误状态
     * 根据不同的错误码设置不同的资源图标，内容等
     */
    private fun setErrorStatus(errorMessage: ErrorMessage?){
        errorMessage?.let { error ->
            binding.containerErrorInfo.visibility = VISIBLE
            when(error.errorCode){
                ApiError.dataIsNullCode ->{
                    binding.ivStatus.setImageResource(emptyResourceId)
                    binding.tvErrorInfo.text = emptyText
                }
                ApiError.connectionErrorCode,ApiError.timeoutCode ->{
                    binding.ivStatus.setImageResource(networkFailResourceId)
                    binding.tvErrorInfo.text = error.description
                }
                else ->{
                    binding.ivStatus.setImageResource(unknownFailResourceId)
                    binding.tvErrorInfo.text = error.description
                }
            }
        } ?: run {
            binding.containerErrorInfo.visibility  = GONE
        }
    }

    /**
     * 设置重试按钮的监听事件
     */
    fun setRetryClickListener(listener: (View) -> Unit){
        binding.btnRetry.setOnClickListener(listener)
    }

}